package miao_ser

import (
	"encoding/json"
	"errors"
	"fmt"
	"gitee.com/ling1314/origin-utility/config"
	"gitee.com/ling1314/origin-utility/constant"
	"gitee.com/ling1314/origin-utility/db"
	"gitee.com/ling1314/origin-utility/model"
	"gitee.com/ling1314/origin-utility/modules/repository"
	log "github.com/sirupsen/logrus"
	"net"
	"runtime"
	"strconv"
	"sync"
	"time"
)

type TcpClient struct {
	Conn net.Conn
}

var TcpSer *TcpServer

func InitTcpServer() {
	TcpSer = NewServer(config.GlobalCfg.Tcp.Ip, config.GlobalCfg.Tcp.Port)
	go func() {
		err := TcpSer.Start()
		if err != nil {
			log.Error("启动tcp服务失败：", err)
			return
		}
	}()
}
func SendInstruct(clientId int64, inst model.ClientInstruct) error {
	bs, err := Encode(inst)
	if err != nil {
		return err
	}
	if _, ok := TcpSer.clientMap[clientId]; !ok {
		err = errors.New("设备不在线")
		return err
	}
	_, err = TcpSer.clientMap[clientId].Conn.Write(bs)
	if err != nil {
		return err
	}
	log.Debugf("发送指令：%v", inst)
	return nil
}

func LoadIdpCatch() {
	var (
		li  []model.MiaoClient
		err error
	)
	if li, err = repository.MiaoTerminalRepository.FindAll(); err != nil {
		log.Error(err)
		return
	}
	for _, item := range li {
		var (
			cpu         model.IdpLogCpu
			memory      model.IdpLogMemory
			diskPhysics model.IdpLogDisk
			boardBase   model.IdpLogBoard
			sysAbstract model.IdpLogSysAbstract
		)
		if cpu, err = repository.IdpLogRepository.FindLastCpu(item.DeviceID); err != nil {
			log.Error(err)
			return
		}
		if memory, err = repository.IdpLogRepository.FindLastMemory(item.DeviceID); err != nil {
			log.Error(err)
			return
		}
		if diskPhysics, err = repository.IdpLogRepository.FindLastDisk(item.DeviceID); err != nil {
			log.Error(err)
			return
		}
		if boardBase, err = repository.IdpLogRepository.FindLastBoard(item.DeviceID); err != nil {
			log.Error(err)
			return
		}
		if sysAbstract, err = repository.IdpLogRepository.FindLastSysAbstract(item.DeviceID); err != nil {
			log.Error(err)
			return
		}
		db.InfoCatchMaoForIdp[item.DeviceID] = db.IdpCatch{
			CPU:         cpu,
			Memory:      memory,
			DiskPhysics: diskPhysics,
			BoardBase:   boardBase,
			SysAbstract: sysAbstract,
		}
	}
}

// sendHandsUpInstruct 不要主动通知客户端举手
func sendHandsUpInstruct(conn net.Conn) (err error) {
	inst := model.ClientInstruct{
		Code:      constant.HandsUp,
		ServeTime: time.Now().Unix(),
	}
	var bs []byte
	bs, err = Encode(inst)
	if err != nil {
		return err
	}
	_, err = conn.Write(bs)
	return
}

func sendInstructForSetDeviceId(clientId int64, conn net.Conn) (err error) {
	inst := model.ClientInstruct{
		Code:      constant.SetDeviceId,
		ServeTime: time.Now().Unix(),
		Body:      strconv.FormatInt(clientId, 10),
	}
	var bs []byte
	bs, err = Encode(inst)
	if err != nil {
		return err
	}
	_, err = conn.Write(bs)
	return
}

func IsOnline(clientId int64) (b bool) {
	_, b = TcpSer.clientMap[clientId]
	return b
}

func NewClient(conn net.Conn) *TcpClient {
	client := &TcpClient{
		Conn: conn,
	}
	return client
}

// listenMsg 将消息解码还原为 ClientResponse 对象，然后处理消息
func listenMsg(s *TcpServer, conn net.Conn) {
	for {
		var (
			msg model.ClientResponse
			bs  []byte
			err error
		)
		bs, err = Decode2(conn)
		if err != nil {
			if needReadError(err) {
				s.clientOffline(conn)
				continue
			}
			log.Error(err)
		}
		err = json.Unmarshal(bs, &msg)
		if err != nil {
			log.Error(err)
		}
		s.HandMsg(msg, conn)
	}
}

///////////////////// TcpServer 代码  /////////////////////////////////

type TcpServer struct {
	Ip          string
	Port        int
	clientMap   map[int64]*TcpClient
	clientMutex sync.Mutex

	vaHandler *vaHandler
	viHandler *viHandler
}

func NewServer(ip string, port int) *TcpServer {
	server := &TcpServer{
		Ip:          ip,
		Port:        port,
		clientMap:   make(map[int64]*TcpClient),
		clientMutex: sync.Mutex{},
		vaHandler:   NewVaHandler(),
		viHandler:   NewViHandler(),
	}
	return server
}

func (s *TcpServer) Start() error {
	listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", s.Ip, s.Port))
	defer listener.Close()
	if err != nil {
		log.Errorf("启动 tcp 监听服务失败,监听地址为：%s", fmt.Sprintf("%s:%d", s.Ip, s.Port))
		return err
	}
	for {
		con, err := listener.Accept()
		if err != nil {
			log.Errorf("客户端连接失败：%s", err)
			continue
		}
		// 开启协程，监听客户端消息
		go listenMsg(s, con)
	}
}

func (s *TcpServer) clientOnline(clientId int64, conn net.Conn) {
	s.clientMutex.Lock()
	s.clientMap[clientId] = NewClient(conn)
	s.clientMutex.Unlock()
}

func (s *TcpServer) clientOffline(conn net.Conn) {
	// 移除 map中的连接记录
	s.clientMutex.Lock()
	for key := range s.clientMap {
		if s.clientMap[key].Conn == conn {
			delete(s.clientMap, key)
		}
	}
	s.clientMutex.Unlock()
	// 关闭连接，释放句柄
	_ = conn.Close()
	// 通知协程退出
	runtime.Goexit()
}
